package il.ac.tau.cg.ex5.rendering;

import il.ac.tau.cg.ex5.obj.ObjEntity;
import il.ac.tau.cg.ex5.util.Color;
import il.ac.tau.cg.ex5.util.Face;
import il.ac.tau.cg.ex5.util.Vertex;

import java.nio.FloatBuffer;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.fixedfunc.GLPointerFunc;

import com.jogamp.common.nio.Buffers;

public class VertexArraysRenderer extends Renderer
{
	private static final String NAME = "Vertex arrays";
	
	private int roomVertexCount;
	private FloatBuffer roomVertexBuffer;
	private FloatBuffer roomNormalBuffer;
	private FloatBuffer roomColorBuffer;
	
	private int objVertexCount;
	private FloatBuffer objVertexBuffer;
	private FloatBuffer objNormalBuffer;
	private FloatBuffer objColorBuffer;
	
	public VertexArraysRenderer(ObjEntity roomEntity, ObjEntity objEntity)
	{
		Face[] roomFaces = roomEntity.getFaces();
		
		roomVertexCount = 4 * roomFaces.length;
		roomVertexBuffer = createVertexBuffer(roomFaces);
		roomNormalBuffer = createNormalBuffer(roomFaces);
		roomColorBuffer = createColorBuffer(roomFaces);
		
		Face[] objFaces = objEntity.getFaces();
		
		objVertexCount = 4 * objFaces.length;
		objVertexBuffer = createVertexBuffer(objFaces);
		objNormalBuffer = createNormalBuffer(objFaces);
		objColorBuffer = createColorBuffer(objFaces);
	}
	
	@Override
	public String getName()
	{
		return NAME;
	}
	
	@Override
	protected void renderRoom(GL2 gl)
	{
		internalRender(gl, roomVertexBuffer, roomNormalBuffer, roomColorBuffer, roomVertexCount);
	}
	
	@Override
	protected void renderObj(GL2 gl)
	{
		internalRender(gl, objVertexBuffer, objNormalBuffer, objColorBuffer, objVertexCount);
	}
	
	private void internalRender(GL2 gl, FloatBuffer vertexBuffer,
			FloatBuffer normalBuffer, FloatBuffer colorBuffer, int vertexCount)
	{
		gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
		gl.glEnableClientState(GLPointerFunc.GL_COLOR_ARRAY);
		
		gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
		gl.glNormalPointer(GL.GL_FLOAT, 0, normalBuffer);
		gl.glColorPointer(3, GL.GL_FLOAT, 0, colorBuffer);
		
		gl.glDrawArrays(GL2.GL_QUADS, 0, vertexCount);
		
		gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GLPointerFunc.GL_NORMAL_ARRAY);
		gl.glDisableClientState(GLPointerFunc.GL_COLOR_ARRAY);
	}
	
	private FloatBuffer createVertexBuffer(Face[] faces)
	{
		float[] fVertices = new float[3 * 4 * faces.length];
		
		for (int i = 0; i < faces.length; i++)
		{
			Face face = faces[i];
			
			for (int j = 0; j < 4; j++)
			{
				Vertex vertex = face.vertices[j];
				
				fVertices[12 * i + 3 * j] = vertex.x;
				fVertices[12 * i + 3 * j + 1] = vertex.y;
				fVertices[12 * i + 3 * j + 2] = vertex.z;
			}
		}
		
		return Buffers.newDirectFloatBuffer(fVertices);
	}
	
	private FloatBuffer createNormalBuffer(Face[] faces)
	{
		float[] fNormals = new float[3 * 4 * faces.length];
		
		for (int i = 0; i < faces.length; i++)
		{
			Face face = faces[i];
			
			for (int j = 0; j < 4; j++)
			{
				Vertex normal = face.normals[j];
				
				fNormals[12 * i + 3 * j] = normal.x;
				fNormals[12 * i + 3 * j + 1] = normal.y;
				fNormals[12 * i + 3 * j + 2] = normal.z;
			}
		}
		
		return Buffers.newDirectFloatBuffer(fNormals);
	}
	
	private FloatBuffer createColorBuffer(Face[] faces)
	{
		float[] fColors = new float[3 * 4 * faces.length];
		
		for (int i = 0; i < faces.length; i++)
		{
			Face face = faces[i];
			
			for (int j = 0; j < 4; j++)
			{
				Color color = face.colors[j];
				
				fColors[12 * i + 3 * j] = color.r;
				fColors[12 * i + 3 * j + 1] = color.g;
				fColors[12 * i + 3 * j + 2] = color.b;
			}
		}
		
		return Buffers.newDirectFloatBuffer(fColors);
	}
}
